package com.xyz.mockapi.common.util;

import com.xyz.mockapi.common.annotation.ExcelValidate;
import com.xyz.mockapi.common.exception.ExcelImportException;

import java.lang.reflect.Field;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.List;

/**
 * 通用Excel导入校验工具（无需修改，适配所有实体类）
 */
public class ExcelValidateUtil {

    /**
     * 通用校验方法：反射扫描注解，动态校验列表数据
     * @param dataList 导入的实体类列表
     * @param <T> 任意实体类
     */
    public static <T> void validateExcelData(List<T> dataList) {
        if (dataList.isEmpty()) {
            throw new ExcelImportException("导入失败", "Excel文件无有效数据");
        }

        // 遍历每一行数据（行号从2开始，1为表头）
        for (int i = 0; i < dataList.size(); i++) {
            int rowNum = i + 2;
            T entity = dataList.get(i);
            validateSingleEntity(entity, rowNum); // 校验单行数据
        }
    }

    /**
     * 校验单个实体类（反射获取字段和注解）
     */
    private static <T> void validateSingleEntity(T entity, int rowNum) {
        Class<?> clazz = entity.getClass();
        Field[] fields = clazz.getDeclaredFields(); // 获取所有字段（包括private）

        for (Field field : fields) {
            // 仅处理带有@ExcelValidate注解的字段
            if (!field.isAnnotationPresent(ExcelValidate.class)) {
                continue;
            }

            ExcelValidate validate = field.getAnnotation(ExcelValidate.class);
            String fieldName = validate.fieldName(); // 字段中文名称（前端提示用）
            String dataType = validate.dataType();    // 允许的数据类型
            boolean required = validate.required();  // 是否必填
            String[] allowValues = validate.allowValues(); // 允许的取值范围

            try {
                field.setAccessible(true); // 允许访问private字段
                Object fieldValue = field.get(entity); // 获取字段值

                // 1. 必填校验
                if (required && fieldValue == null) {
                    throw new ExcelImportException(
                            "字段为空",
                            String.format("第%d行，【%s】字段为空，请填写值", rowNum, fieldName)
                    );
                }
                if (required && fieldValue instanceof String && ((String) fieldValue).trim().isEmpty()) {
                    throw new ExcelImportException(
                            "字段为空",
                            String.format("第%d行，【%s】字段为空字符串，请填写值", rowNum, fieldName)
                    );
                }

                // 2. 数据类型校验（字段值不为空时才校验）
                if (fieldValue != null) {
                    validateDataType(fieldValue, dataType, rowNum, fieldName, validate.dateFormat());

                    // 3. 取值范围校验（有配置时才校验）
                    if (allowValues.length > 0) {
                        validateAllowValues(fieldValue, allowValues, rowNum, fieldName);
                    }
                }

            } catch (IllegalAccessException e) {
                throw new ExcelImportException(
                        "反射异常",
                        String.format("第%d行，【%s】字段校验失败：%s", rowNum, fieldName, e.getMessage())
                );
            } catch (ExcelImportException e) {
                // 直接抛出已拼接好的错误信息
                throw e;
            } catch (Exception e) {
                throw new ExcelImportException(
                        "未知错误",
                        String.format("第%d行，【%s】字段校验异常：%s", rowNum, fieldName, e.getMessage())
                );
            }
        }
    }

    /**
     * 数据类型校验（支持String/Integer/Long/Double/Date）
     */
    private static void validateDataType(Object value, String dataType, int rowNum, String fieldName, String dateFormat) {
        String valueStr = value.toString();
        switch (dataType) {
            case "Integer":
                try {
                    Integer.parseInt(valueStr);
                } catch (NumberFormatException e) {
                    throw new ExcelImportException(
                            "类型错误",
                            String.format("第%d行，【%s】字段值【%s】不是有效整数", rowNum, fieldName, valueStr)
                    );
                }
                break;
            case "Long":
                try {
                    Long.parseLong(valueStr);
                } catch (NumberFormatException e) {
                    throw new ExcelImportException(
                            "类型错误",
                            String.format("第%d行，【%s】字段值【%s】不是有效长整数", rowNum, fieldName, valueStr)
                    );
                }
                break;
            case "Double":
                try {
                    Double.parseDouble(valueStr);
                } catch (NumberFormatException e) {
                    throw new ExcelImportException(
                            "类型错误",
                            String.format("第%d行，【%s】字段值【%s】不是有效小数", rowNum, fieldName, valueStr)
                    );
                }
                break;
            case "Date":
                try {
                    new SimpleDateFormat(dateFormat).parse(valueStr);
                } catch (ParseException e) {
                    throw new ExcelImportException(
                            "类型错误",
                            String.format("第%d行，【%s】字段值【%s】不是有效日期（格式：%s）", rowNum, fieldName, valueStr, dateFormat)
                    );
                }
                break;
            case "String":
                // String类型无需额外校验（默认支持）
                break;
            default:
                throw new ExcelImportException(
                        "配置错误",
                        String.format("第%d行，【%s】字段配置的类型【%s】不支持", rowNum, fieldName, dataType)
                );
        }
    }

    /**
     * 取值范围校验（如仅允许0或1）
     */
    private static void validateAllowValues(Object value, String[] allowValues, int rowNum, String fieldName) {
        String valueStr = value.toString();
        if (!Arrays.asList(allowValues).contains(valueStr)) {
            throw new ExcelImportException(
                    "取值错误",
                    String.format(
                            "第%d行，【%s】字段值【%s】无效，仅允许：%s",
                            rowNum, fieldName, valueStr, String.join("、", allowValues)
                    )
            );
        }
    }
}